﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net.Http;
using System.Threading.Tasks;

using Newtonsoft.Json;

using Sustainalytics.ClientDW.Entities;
using Sustainalytics.DataLayer.ConnectionStrings;
using Sustainalytics.DataLayer.Shared;
using Sustainalytics.Entities;
using Sustainalytics.Entities.ConnectionStrings;
using Sustainalytics.Auth.Common;
using Sustainalytics.Entities.ESGRatings;
using Sustainalytics.ESGRatings.BusinessLogic.Exceptions;
using Sustainalytics.LongRunningTaskManager;
using Sustainalytics.LongRunningTaskManager.Interface;
using Sustainalytics.Utils;



namespace Sustainalytics.ESGRatings.Tasks
{
    using System.Net.Http.Formatting;
    using System.Net.Http.Headers;

    using Microsoft.Owin.Security;
    using Newtonsoft.Json.Serialization;

    using Sustainalytics.Auth.Common;

    public class EsgCompanyReportDownloadTask : ILongRunningTask
    {
        private readonly string _clientDWConnectionString;

        public EsgCompanyReportDownloadTask()
        {
            var clientPlatformConnectionString = ConfigurationManager.ConnectionStrings["ClientPlatform"].ConnectionString;

            var connectionStringsManager =
                ConnectionStringsManager.GetInstance(
                    ConnectionStringsRepository.GetInstance(clientPlatformConnectionString),
                    DateTime.Today.AddHours(
                        double.Parse(ConfigurationManager.AppSettings["ConnectionStringsPollingStartHourUtc"])),
                    TimeSpan.FromHours(double.Parse(ConfigurationManager.AppSettings["ConnectionStringsPollingDurationHours"])),
                TimeSpan.FromMinutes(double.Parse(ConfigurationManager.AppSettings["ConnectionStringsPollingFrequencyMinutes"])));
            _clientDWConnectionString = connectionStringsManager.GetConnectionString(ConnectionStringType.ClientDW);
        }

        public LongRunningTaskTypeEnum Type
        {
            get { return LongRunningTaskTypeEnum.ESGCompanyReportPDF; }
        }

        public object Start(LongRunningTaskContext context)
        {            
            var uri = new Uri(string.Format("{0}/api/v1", ConfigurationManager.AppSettings["ESGRatingServiceUrl"]));

            CompanyReportEventSource.Log.TryUrl(uri.ToString());

            var parameters = GetReportParameters(context.ParamJson,this._clientDWConnectionString);
            
            return TryGenerateReport(context, uri, parameters);
        }

        private static EsgCompanyReportParameters GetReportParameters(string esgReportParams, string clientDWConnectionString)
        {
            var parameters = JsonConvert.DeserializeObject<EsgCompanyReportParameters>(esgReportParams);

            var company = new RepositoryCollection<CorporateData>(clientDWConnectionString).Read(parameters.CompanyId);

            if (company.ResearchParentId.HasValue)
            {
                parameters.CompanyId = company.ResearchParentId.Value;
            }

            parameters.HasComprehensiveResearch = company.HasEsgResearch;

            parameters.FileName = GetFileName(parameters.CompanyId, company);
            return parameters;
                format = "{0}_ESGSummaryReport_{1}.pdf";
        }

        private static string GetFileName(Guid companyId, CorporateData company)
        {
            var format = "{0}_ESGRatingsReport_{1}.pdf";

            if (company.HasFocusedRatingsResearch)
            {
                format = "{0}_FocusedRatingsReport_{1}.pdf";
            }

            var reportFileName = RemoveIllegalCharacters.Replace(company.CompanyName, "_");

            var fileName = string.Format(format, reportFileName, companyId);
            return fileName;
        }

        private static LongRunningTaskFileInMemResult TryGenerateReport(
            LongRunningTaskContext context,
            Uri uri,
            EsgCompanyReportParameters parameters)
        {
            if (uri == null)
            {
                throw new ArgumentNullException("uri");
            }

            if (parameters == null)
            {
                throw new ArgumentNullException("parameters");
            }

            using (var client = new ESGRatingsClient(uri, parameters, context.Ticket))
            {
                var executionResult = client.PostAsync().Result;

                if (executionResult.IsSuccessStatusCode)
                {
                    var result = client.GetResponseMessageAsync(executionResult).Result;
                    if (result != null)
                    {
                        return new LongRunningTaskFileInMemResult
                                   {
                                       FileName = result.FileName,
                                       MimeType = "application/pdf",
                                       Contents = result.FileContent
                                   };
                    }

                    context.SetErrorToContext(6001, "Failed to generate the ESG Company Report for specified parameters");
                    return null;
                }

                var error = client.GetErrorMessageAsync(executionResult).Result;

                if (error != null)
                {
                    context.SetErrorToContext(error.ErrorCode, error.ErrorMessage);
                }
                else
                {
                    context.SetErrorToContext(0, string.Empty);
                }
            }

            return null;
        }
    }

    public class ESGRatingsClient : HttpClient
    {
        private readonly EsgCompanyReportParameters _parameters;

        private readonly string _requestUri;

        private readonly JsonMediaTypeFormatter _jsonMediaTypeFormatter = new JsonMediaTypeFormatter
                                                                    {
                                                                        SerializerSettings = { ContractResolver = new CamelCasePropertyNamesContractResolver() }
                                                                    };

        public ESGRatingsClient(Uri uri, EsgCompanyReportParameters parameters, AuthenticationTicket ticket)
        {
            this._parameters = parameters;
            this._requestUri = string.Format("{0}/company/{1}/esgCompanyReport", uri, parameters.CompanyId);
            var ticketDataFormat = new CustomAccessTokenFormat();
            var accessToken = ticketDataFormat.Protect(ticket);
            this.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            this.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
        }

        public async Task<HttpResponseMessage> PostAsync()
        {
            return await this.PostAsync(this._requestUri, this._parameters, this._jsonMediaTypeFormatter).ConfigureAwait(false);
        }

        public async Task<PdfReportExecutionResult> GetResponseMessageAsync(HttpResponseMessage message)
        {
            return
                await message.Content.ReadAsAsync<PdfReportExecutionResult>(new[] { this._jsonMediaTypeFormatter }).ConfigureAwait(false);
        }

        public async Task<EsgRatingsError> GetErrorMessageAsync(HttpResponseMessage message)
        {
            return
                await message.Content.ReadAsAsync<EsgRatingsError>(new[] { this._jsonMediaTypeFormatter }).ConfigureAwait(false);
        }

}

    public static class LRTMContextExtension
    {
        public static void SetErrorToContext(this LongRunningTaskContext context, int errorCode, string errorMessage)
        {
            context.Title = "Failed to generate the ESG Company Report for specified parameters";
            context.TaskStatus.AddError(
                new LongRunningTaskError { ErrorCode = errorCode, Arguments = new List<string> { errorMessage } });
        }
    }
}
